O記聯合CIB準備於今晚韓琛與泰國佬交易可卡因(古柯鹼)時,來個人贓並獲。建明知道後,假裝打電話給家人,通知韓琛。韓琛一直監聽警方頻道,並指示迪路和傻強四處亂晃,不要前往交易地點。過程中,永仁一直以摩斯密碼與黃sir聯絡。黃sir在得知韓琛監聽頻道後,隨即轉換頻道,並使用舊頻道發出今晚行動取消的指令。韓琛信以為真,指示迪路和傻強可以前往龍鼓灘交易。正當交易完成,黃sir準備先逮捕迪路和傻強將毒品扣下,再衝進屋逮捕韓琛之際,建仁使用簡訊傳送「有內鬼,終止交易」到韓琛所在位置附近的所有手機。
insert
地點大廈三樓insert Location {name:="大廈三樓"};
update
wong
黃sir為有組織罪案及三合會調查科(O記)的警司(SP
),update
其相關property
。
update wong
set {
police_rank:= PoliceRank.SP,
dept:= "有組織罪案及三合會調查科(O記)",
};
insert
數名O記警察insert
黃sir麾下警察。
for i in range_unpack(range(1, 11))
union (
insert Police {
name:= "police_" ++ <str>i,
dept:= "有組織罪案及三合會調查科(O記)",
police_rank:= PoliceRank.SPC,
}
);
update
lau
建明為刑事情報科(CIB)的高級督察(SIP
),update
其相關property
。
update lau
set {
police_rank:= PoliceRank.SIP,
dept:= "刑事情報科(CIB)",
};
insert
數名CIB警察insert
建明麾下警察。
insert Police{
name:= "林國平",
nickname:="大B",
police_rank:= PoliceRank.SSGT,
dept:= "刑事情報科(CIB)",
actors:= (
insert Actor{
name:= "林家棟",
eng_name:= "Gordon",
}
)
};
for name in {"大象", "孖八"}
union (
insert Police {
name:= name,
nickname:= name,
dept:= "刑事情報科(CIB)",
police_rank:= PoliceRank.SGT,
}
);
for i in range_unpack(range(11, 14))
union (
insert Police {
name:= "police_" ++ <str>i,
dept:= "刑事情報科(CIB)",
police_rank:= PoliceRank.SPC,
}
);
insert
數名韓琛小弟insert
數名韓琛小弟,包括兩個小頭目,迪路與傻強。
insert Gangster {
name:= "迪比亞路",
nickname:= "迪路",
gangster_boss:= hon,
gangster_rank:= GangsterRank.Leader,
actors:= (insert Actor {
name:= "林迪安",
eng_name:="Dion",
}),
};
insert Gangster {
name:= "徐偉強",
nickname:= "傻強",
gangster_boss:= hon,
gangster_rank:= GangsterRank.Leader,
actors:= (insert Actor {
name:= "杜汶澤",
eng_name:= "Edward",
}),
};
for i in range_unpack(range(1, 11))
union (
insert Gangster {
name:= "gangster_" ++ <str>i,
gangster_boss:= hon,
gangster_rank:= GangsterRank.Nobody,
}
);
insert
數個提及的地標for loc in {"葵涌碼頭", "三號幹線", "龍鼓灘"}
union (
insert Landmark{
name:= loc,
}
);
insert
ChenLauContact
insert ChenLauContact {
how:= "面對面",
detail:= "黃sir帶隊進入韓琛毒品交易現場",
`when`:= year_2002,
where:= assert_single((select Location filter .name="大廈三樓")),
};
group
- 情境1讓我們假想一下自己是編劇。這個場景的人物相比前面多了不少,我們必須確認從警察的視角來看,各個階級的人力配置合不合理,此時group
會是一個不錯的工具。進行group
之後的操作,大多需要用到它的key
、grouping
及elements
。
首先我們做以下嘗試:
with
區塊選取Police
、PoliceSpy
及GangsterSpy
(建明及永仁也都是警察)命名為p
。with
區塊group p
並依照police_rank
來分類,結果命名為g
。{**}
顯示g
的細節(註1)。with p:= Police union PoliceSpy union GangsterSpy,
g:= (group p by .police_rank),
select g {**};
但這麼一來,結果會非常長,我們舉黃sir為例,因為SP
級別只有他一人。
...
{
id: 10d5423b-15cf-4c4d-89ca-e39b4bfa9902,
grouping: {'police_rank'},
key: {id: 46542b84-47fb-44b8-bdfd-2bc34e924eee, police_rank: SP},
elements: {
default::Police {
is_officer: true,
classic_lines: ['你25號生日嘛!25仔!'],
eng_name: {},
name: '黃志誠',
nickname: '黃sir',
dept: '有組織罪案及三合會調查科(O記)',
police_rank: SP,
id: db630896-bc48-11ee-aae4-df71814b08b4,
},
},
},
...
之所以會得到這麼長的結果是因為使用了{**}
,但是我們的目的僅是想知道各個階級的人數,所以可以做下列修改:
group
的key
可以得到police_rank
(因為這個property
就是我們在by
時使用的),並在g{ }
中命名為police_rank
。group
的elements
得到該分類中每一個object
(即Police
或PoliceSpy
或GangsterSpy
),接著使用count
來計算其數量,並在g{ }
中命名為counts
。police_rank
是一個enum
,所以可以使用order by
對其進行排序,並加上desc
,這麼一來就會改成官階較大的排在前面。with p:= Police union PoliceSpy union GangsterSpy,
g:= (group p by .police_rank),
select g {police_rank:= .key.police_rank,
counts:= count(.elements)}
order by .police_rank desc;
{
{police_rank: SP, counts: 1},
{police_rank: SIP, counts: 1},
{police_rank: SSGT, counts: 1},
{police_rank: SGT, counts: 2},
{police_rank: SPC, counts: 13},
{police_rank: Protected, counts: 1},
}
這麼一來就可以看出:
SP
及SIP
各一位SSGT
一位及SGT
兩位。SPC
十三位。編劇此時可以依據這個結果,來請教相關專業人士這樣的人力配置是否合理。
group
- 情境2假設片場工作人員在休息時間聊到,不知道劇中出現的地名:
此時又是可以好好運用group
的機會囉。因為這次不像上面一樣,有內建的police_rank
可以使用,所以需要使用using
來組合出想要如何分類的操作。
針對第一個問題:
name property
使用len
,並取名為name_length
,這樣就可以將其放在by
之後來分類。group
的key
得到剛剛定義的name_length
,並在g{ }
中命名為name_length
。group
的elements
得到該分類中每一個Place
,接著使用count
來計算其數量,並在g{ }
中命名為counts
。group
的elements
得到name property
,並在g{ }
中命名為names
。order by
對name_length
進行排序,並加上desc
,這麼一來長度較長的地名就會顯示在前面了。with g:= (group Place
using name_length:= len(.name)
by name_length),
select g {name_length:= .key.name_length ,
counts:= count(.elements),
names:= .elements.name}
order by .name_length desc;
{
{name_length: 6, counts: 1, names: {'Hi-Fi鋪'}},
{name_length: 4, counts: 3, names: {'大廈三樓', '葵涌碼頭', '三號幹線'}},
{name_length: 3, counts: 2, names: {'警察局', '龍鼓灘'}},
{name_length: 2, counts: 3, names: {'佛堂', '天台', '警校'}},
}
結果發現長度最長的地名是Hi-Fi鋪,長度為6。
針對第二個問題,只需將order by
的目標改為counts
即可。
with g:= (group Place
using name_length:= len(.name)
by name_length),
select g {name_length:= .key.name_length ,
counts:= count(.elements),
names:= .elements.name}
order by .counts desc;
{
{name_length: 4, counts: 3, names: {'大廈三樓', '葵涌碼頭', '三號幹線'}},
{name_length: 2, counts: 3, names: {'佛堂', '天台', '警校'}},
{name_length: 3, counts: 2, names: {'警察局', '龍鼓灘'}},
{name_length: 6, counts: 1, names: {'Hi-Fi鋪'}},
}
結果發現地名長度為4及2的組別都出現三次。
insert
此場景的Scene
這裡選擇人物時,其實也可以像前面一樣使用Police
及Gangster
。但這麼一來,就是假設要選取全部的Police
及Gangster
,如果之後我們修改了前面幾個場景的query,在現在這種人物比較多的場景會難以偵錯(您可以假想Scene
被極度簡化,只包含重要演員,但配角及台前幕後許多工作人員都未計入)。
所以我們這邊示範使用with
搭配filter
,限縮選取範圍。
with policemen:= (
select Police
filter .dept in {"有組織罪案及三合會調查科(O記)",
"刑事情報科(CIB)"}
),
gangsters:= (select Gangster filter .gangster_boss=hon)
insert Scene {
title:= "有內鬼終止交易",
detail:= "O記聯合CIB準備於今晚韓琛與泰國佬交易可卡因(古柯鹼)時,來個" ++
"人贓並獲。建明知道後,假裝打電話給家人,通知韓琛。韓琛一直監" ++
"聽警方頻道,並指示迪路和傻強四處亂晃,不要前往交易地點。過程中," ++
"永仁一直以摩斯密碼與黃sir聯絡。黃sir在得知韓琛監聽頻道後,隨即" ++
"轉換頻道,並使用舊頻道發出今晚行動取消的指令。韓琛信以為真,指示" ++
"迪路和傻強可以前往龍鼓灘交易。正當交易完成,黃sir準備先逮捕迪路" ++
"和傻強將毒品扣下,再衝進屋逮捕韓琛之際,建仁使用簡訊傳送「有內鬼" ++
",終止交易」到韓琛所在位置附近的所有手機。",
who:= policemen union gangsters union {chen, lau, hon},
`when`:= year_2002,
where:= (select Place filter .name="大廈三樓" or .name="龍鼓灘"),
remarks:= "1.假設國平官階為`SSGT`,大象與孖八官階為`SGT`。"
};
註1:或許您會很想只顯示key
裡面的police_rank
及elements
裡面的name
,卻發現不知道怎麼達成。您可能會做以下嘗試:
#❌
with p:= Police union PoliceSpy union GangsterSpy,
g:= (group p by .police_rank),
select g {key {police_rank},
elements {name}};
但正確的語法是需要加上:
:
#✅
with p:= Police union PoliceSpy union GangsterSpy,
g:= (group p by .police_rank),
select g {key: {police_rank},
elements: {name}};
{
{
key: {police_rank: Protected},
elements: {default::PoliceSpy {name: '陳永仁'}}},
{
key: {police_rank: SPC},
elements: {
default::Police {name: 'police_1'},
default::Police {name: 'police_2'},
default::Police {name: 'police_3'},
default::Police {name: 'police_4'},
default::Police {name: 'police_5'},
default::Police {name: 'police_6'},
default::Police {name: 'police_7'},
default::Police {name: 'police_8'},
default::Police {name: 'police_9'},
default::Police {name: 'police_10'},
default::Police {name: 'police_11'},
default::Police {name: 'police_12'},
default::Police {name: 'police_13'},
},
},
{
key: {police_rank: SGT},
elements: {default::Police {name: '大象'}, default::Police {name: '孖八'}}
},
{key: {police_rank: SSGT}, elements: {default::Police {name: '林國平'}}},
{key: {police_rank: SIP}, elements: {default::GangsterSpy {name: '劉建明'}}},
{key: {police_rank: SP}, elements: {default::Police {name: '黃志誠'}}},
}
這也是一個我們經常會突然失憶的地方,分享給大家作為參考。
update
。insert
。insert
。